<template>
  <div>
    <!-- 图谱容器，my-graph样式类设置了高度 ，点击容器关闭右键菜单-->
    <div ref="myPage" class="my-graph" @click="isShowNodeMenuPanel = false">
      <!--显示提示信息-->
      <div class="notice-message">
        注意：删除任一节点前请先确保其没有子节点！
      </div>
      <!-- 引用关系图组件，并传递配置项 -->
      <RelationGraph ref="graphRef" :options="graphOptions">
        <!-- 为每个节点定义模板，动态绑定类，用于选中效果的显示 -->
        <template #node="{node}">
          <!--:class="...": 动态绑定CSS类，根据节点是否被选中应用不同的样式。-->
          <!--$event：事件对象，包含了事件的所有相关信息，如点击位置、时间等。后面方法中计算菜单位置要用到-->
          <div
            @contextmenu="showNodeMenu($event, node)"
            @click="handleNodeExpandCollapse(node)"
            :class="{ 'node-container-selected': selectedNodeId === node.id }"
            class="expand-collapse-button"
          >
            <!-- 显示节点名称及通过一个加减号展示节点展开状态 -->
            {{ node.expanded ? '-' : '+' }}
            {{ node.text }}
          </div>
        </template>
      </RelationGraph>
    </div>
    <!-- 节点右键菜单 -->
    <div ref="nodeMenu" v-show="isShowNodeMenuPanel" :style="{left: nodeMenuPanelPosition.x + 'px', top: nodeMenuPanelPosition.y + 'px' }" style="z-index: 999;padding:10px;background-color: #ffffff;border:#eeeeee solid 1px;box-shadow: 0px 0px 8px #cccccc;position: absolute;border-radius: 10px;">
      <div style="line-height: 25px;padding-left: 10px;color: #888888;font-size: 12px;">对这个节点进行操作：</div>
      <!-- 菜单项，点击后调用 doAction 方法 -->
      <div class="node-menu-item" @click="doAction('增加子节点')">增加子节点</div>
      <div class="node-menu-item" @click="doAction('删除该节点')">删除该节点</div>
      <div class="node-menu-item" @click="doAction('查看节点信息')">查看节点信息</div>
      <div class="node-menu-item" @click="doAction('修改节点信息')">修改节点信息</div>
    </div>
    <!-- 添加节点信息对话框 -->
    <el-dialog :visible.sync="dialogVisible" title="增加新节点"><!--:visible.sync="dialogVisible": 控制对话框的显示与隐藏-->
      <el-form><!--表单组件-->
        <el-form-item label="节点名称"><!--定义一个表单项，其标签（label）为“节点名称”-->
          <el-input v-model="newNode.name" placeholder="请输入节点名称"></el-input><!--placeholder属性提供了输入框的占位符文本。-->
        </el-form-item>
        <el-form-item label="节点详情">
          <el-input type="textarea" v-model="newNode.details" placeholder="请输入节点详情"></el-input><!--多行文本框（textarea）-->
        </el-form-item>
      </el-form>
      <div slot="footer" ><!--定义了对话框底部的内容区域，用于放置操作按钮。-->
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="addNewNode">确 定</el-button><!--type="primary" 使按钮具有主要按钮的样式，突出显示为蓝色-->
      </div>
    </el-dialog>
    <!-- 查看节点信息对话框 -->
    <el-dialog :visible.sync="viewDialogVisible" title="查看节点信息">
      <el-form>
        <el-form-item label="节点名称">
          <el-input v-model="activeNode.name" placeholder="节点名称" disabled></el-input>
        </el-form-item>
        <el-form-item label="节点详情">
          <el-input type="textarea" v-model="activeNode.details" placeholder="节点详情" disabled></el-input><!--disabled属性使得输入框处于不可编辑状态。-->
        </el-form-item>
      </el-form>
      <div slot="footer" >
        <el-button @click="viewDialogVisible = false">关闭</el-button>
      </div>
    </el-dialog>
    <!-- 修改节点信息对话框 -->
    <el-dialog :visible.sync="editDialogVisible" title="修改节点信息">
      <el-form>
        <el-form-item label="节点名称">
          <el-input v-model="activeNode.name" placeholder="节点名称"></el-input>
        </el-form-item>
        <el-form-item label="节点详情">
          <el-input type="textarea" v-model="activeNode.details" placeholder="节点详情"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer">
        <el-button @click="editDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="updateNode">保存</el-button><!--type="primary" 使按钮具有主要按钮的样式，突出显示为蓝色-->
      </div>
    </el-dialog>
  </div>
</template>


<script>
import { listProduct, getProduct, delProduct, addProduct, updateProduct,} from "@/api/system/product";
import RelationGraph from 'relation-graph';

export default {
  name: 'Demo4NodeStyle',
  components: {
    RelationGraph,
  },
  data() {
    return {
      currentNode: null, // 初始化 currentNode,用于节点菜单储存节点信息
      selectedNodeId: null, // 用于保存当前选中节点的ID
      // 控制菜单显示和位置的变量
      isShowNodeMenuPanel: false,//用于是否展示节点菜单
      nodeMenuPanelPosition: { x: 0, y: 0 },//节点菜单位置
      dialogVisible: false,//关闭展示对话框

      newNode: {
        name: '',
        details: ''
      },
      viewDialogVisible: false,//显示对话框
      editDialogVisible: false,//编辑对话框
      activeNode: {
        id: null,
        name: '',
        details: ''
      },
      // 图谱组件的配置项
      graphOptions: {

        allowShowMiniToolBar: false,
        defaultLineColor: 'rgba(255, 255, 255, 0.6)',
        defaultNodeColor: 'transparent',
        defaultNodeBorderWidth: 0,
        defaultNodeBorderColor: 'transparent',
        defaultNodeFontColor: '#ffffff',
        defaultNodeShape: 1,
        toolBarDirection: 'h',
        toolBarPositionH: 'right',
        toolBarPositionV: 'bottom',
        defaultPloyLineRadius: 10,
        defaultLineShape: 6,
        defaultJunctionPoint: 'lr',
        layout: {
          layoutName: 'tree',
          from: 'right',
          'min_per_width': 310,
          'min_per_height': 70,
        }
      }
    };
  },
  // 生命周期函数，用于初始化数据
  mounted() {
    this.getList(); // 调用 getList 方法，从后端获取数据
  },

  methods: {
    // 从后端获取产业链图谱数据
    getList() {
      this.loading = true;
      listProduct().then(response => {
        //console.log(response);
        // 后端返回的数据是树形结构
        const graphData = this.transformDataForGraph(response.data);
        this.$refs.graphRef.setJsonData(graphData);//将转换后的数据设置到RelationGraph组件上。使用Vue的ref来引用组件，并调用组件的setJsonData方法。
        this.loading = false;
      }).catch(error => {
        console.error("Error fetching data: ", error);
      });
    },
    // 将后端数据转换为 RelationGraph 需要的格式
    transformDataForGraph(data) {
      //console.log('原始数据:', data); // 打印原始后端数据
      const graphData = { nodes: [], lines: [] };
      data.forEach(item => {// 遍历从后端接收到的每个数据项
        //console.log('当前处理的项:', item); // 打印当前处理的每一项
        graphData.nodes.push({
          id: item.productId.toString(),
          text: item.productName,
          details: item.productDetails ,
          expanded: item.expanded,
        });

        if (item.parentId != item.productId) {
          graphData.lines.push({
            from: item.parentId.toString(),//使用toString()方法转换parentId和productId为字符串。
            to: item.productId.toString(),
          });
        }
      });
      //console.log('转换后的数据:', graphData); // 打印转换后的数据
      return graphData;
    },
    // 显示节点菜单的方法
    showNodeMenu($event, node) {
      //console.log('在 showNodeMenu 中的节点对象:', node);
      this.selectedNodeId = node.id; // 设置当前选中的节点ID
      const _base_position = this.$refs.myPage.getBoundingClientRect();
      this.nodeMenuPanelPosition.x = $event.clientX - _base_position.x;
      this.nodeMenuPanelPosition.y = $event.clientY - _base_position.y;
      this.isShowNodeMenuPanel = true;//显示右键菜单
      getProduct(node.id)//获取节点详细信息
        .then(response => {
          //console.log(response);
          this.currentNode = {
            id: response.data.productId,
            text: response.data.productName,
            details: response.data.productDetails,
            expanded: response.data.expanded
          };
        })
        .catch(error => {
          console.error("Error fetching node details: ", error);
        });
      //console.log('设置为 currentNode 的对象:', this.currentNode);
    },
    // 菜单操作的方法
    doAction(action) {
      this.$notify({//显示一个通知
        title: '成功',
        message: `对节点【${this.currentNode.text}】进行了：${action}`,
        type: 'success'
      });
      this.isShowNodeMenuPanel = false;
      switch(action) {
        case '增加子节点':
          // 清除新节点数据并显示添加节点的对话框
          this.newNode = { name: '', details: '' };
          this.dialogVisible = true; // 显示对话框
          break;
        case '删除该节点':
          this.deleteNode();
          break;
        case '查看节点信息':
          this.viewNodeDetails();
          break;
        case '修改节点信息':
          this.editNodeDetails();
          break;
      }
    },

    //增加子节点的方法
    addNewNode() {
      // 检查是否有新节点的名称和详情输入
      if (!this.newNode.name) {
        // 如果没有输入名称，则不执行添加操作，并提示用户
        this.$message.error('请输入节点名称');
        return;
      }
      // 调用API添加节点
      const postData = {
        productName: this.newNode.name,
        productDetails: this.newNode.details,
        parentId: this.currentNode.id, // 使用当前节点的ID作为新节点的parentId
      };
      addProduct(postData).then(response => {
        //console.log(response);
        this.$message.success('节点添加成功');
        this.dialogVisible = false; // 关闭对话框
        this.getList(); // 刷新图谱

      }).catch(error => {
        this.$message.error('节点添加失败: ' + error.message);
      });
    },
    //删除该节点的方法
    deleteNode() {
      //console.log(node.details)
      this.$confirm('此操作将永久删除该节点, 是否继续?', '提示', {//Element UI的$confirm方法显示一个确认对话框
        confirmButtonText: '确定',//confirmButtonText和cancelButtonText分别设置确认和取消按钮的文本。
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        delProduct(this.currentNode.id).then(response => {
          console.log(response);
          this.$message.success('节点删除成功');
          this.getList(); // 刷新数据
        }).catch(error => {
          this.$message.error('节点删除失败: ' + error.message);
        });
      }).catch(() => {
        this.$message.success('取消删除成功');
      });
    },
    //查看节点信息的方法
    viewNodeDetails() {
      this.activeNode = {
        id: this.currentNode.id,
        name: this.currentNode.text,
        details: this.currentNode.details

      };
      //console.log(this.activeNode); // 这行会在控制台输出activeNode的当前值
      this.viewDialogVisible = true;
    },
    //修改节点信息的方法
    editNodeDetails() {
      this.activeNode = {
        id: this.currentNode.id,
        name: this.currentNode.text,
        details: this.currentNode.details
      };
      //console.log(this.activeNode); // 这行会在控制台输出activeNode的当前值
      this.editDialogVisible = true;

    },
    updateNode() {
      const updateData = {
        productId: this.activeNode.id,
        productName: this.activeNode.name,
        productDetails: this.activeNode.details,
      };

      updateProduct(updateData).then(response => {
        this.$message.success('节点信息修改成功');
        this.editDialogVisible = false;
        this.getList(); // 刷新图谱
      }).catch(error => {
        this.$message.error('节点信息修改失败: ' + error.message);
      });
    },
    // 添加方法来处理节点的展开/收缩
    handleNodeExpandCollapse(node) {
      //console.log(node)
      // 切换节点的展开状态
      const newExpandedStatus = !node.expanded;
      updateProduct({ productId: node.id, expanded: newExpandedStatus })
        .then(() => {
          this.$message.success('节点状态更新成功');
          // 更新当前节点的展开状态
          node.expanded = newExpandedStatus;
          // 调用 RelationGraph 组件的 refresh 方法来刷新图表
          this.$refs.graphRef.refresh();
        })
        .catch(error => {
          this.$message.error('节点状态更新失败: ' + error.message);
        });
    },
  }
};
</script>

<style lang="scss" scoped>
// 移除图谱的默认背景
::v-deep .rel-map {
  background: none !important;/* 设置背景为无，!important 确保此样式覆盖任何其他背景设置 */
}

//提示信息样式
.notice-message {
  position: absolute; /* 绝对定位，使元素脱离文档流并可以设置确切位置 */
  left: 10px; /* 距离包含元素左边界10像素 */
  top: 10px; /* 距离包含元素顶边界10像素 */
  background-color: rgba(255,255,255, 0.3); /* 背景颜色设置为半透明的白色 */
  border-radius: 10px; /* 边角的圆弧半径设置为10像素 */
  font-size: 14px; /* 字体大小为12像素 */
  color: #ffffff; /* 字体颜色为白色 */
  padding: 10px; /* 内边距为10像素 */
}

// 定义图谱背景渐变
.my-graph{
  background: linear-gradient(to right, rgb(16, 185, 129), rgb(101, 163, 13));
  height:calc(100vh - 60px);
}

// 定义选中节点的样式
.node-container-selected {
  border: 3px solid #4a752c; /* 边框颜色和宽度 */
  background-color: rgba(164, 214, 142, 0.3); /* 节点的背景颜色，透明度降低以呈现半透明效果 */
  border-radius: 10px; /* 圆角边框 */
  box-shadow: 0 2px 4px rgba(74, 117, 44, 0.5); /* 阴影效果，颜色和透明度*/
  padding: 4px; /* 内边距*/

}

//定义节点及展开按钮及鼠标样式
.expand-collapse-button {
  cursor: pointer; /* 将鼠标样式设置为手形，表示这是一个可点击的元素 */
  color: #ffffff; /* 按钮的颜色 */
  font-weight: bold; /* 加粗字体 */
}

// 定义节点的菜单样式
.node-menu {
  z-index: 999;
  background-color: #ffffff;
  border: #eeeeee solid 1px;
  box-shadow: 0px 0px 8px #cccccc;
  border-radius: 10px;
}

// 定义菜单项的样式
.node-menu-item {
  padding: 10px;
  border-top: #efefef solid 1px;
  cursor: pointer;
}

// 定义菜单项鼠标悬停的样式
.node-menu-item:hover {
  background-color: rgba(66,187,66,0.2);
}

</style>
